home *** CD-ROM | disk | FTP | other *** search
- #!/usr/bin/perl
-
- #BEGIN {$^W=1};
-
- use Gimp::Feature qw(perl-5.005 gtk-1.2);
- use Gimp (':consts','__','N_');
- use Gimp::Fu;
- use Gtk;
- use Gtk::Gdk;
- use Gimp::UI (); # for the logo
- use POSIX 'strftime';
-
- #Gimp::set_trace(TRACE_ALL);
-
- my $ex; # average font width for default font
- my $ey; # average font height for default font
-
- my $window; # the main window
- my $clist; # the list of completions
- my $rlist; # the results list
- my $inputline; # the input entry
- my $result; # the result entry
- my $synopsis; # the synopsis label
- my $statusbar; # the statusbar
- my $cinfo; # command info
-
- my $idle; # the idle function id
-
- my($blurb,$help,$author,$copyright,$date,$type,$args,$results);
- my @args; # the arguments of the current function
-
- my @function; # the names of all functions
- my %function; # the same as hash
- my @completion; # list of completions
- my @compdata; # index completion -> data
- my %plugin_info;# function -> [...]
-
- sub refresh {
- undef %function;
- @function = Gimp->procedural_db_query("","","","","","","");
- @function{@function}=(1) x @function;
- eval {
- my ($a, $b, $c, $d, $e, $f) = Gimp->plugins_query("");
- for $i (0..$#$a) {
- $plugin_info{$f->[$i]} = [map $_->[$i], $a, $b, $c, $d, $e];
- }
- }
- }
-
- sub get_words {
- my $text = $inputline->get_text;
- my $i = 0;
- my($p,$idx,$pos);
- my $word;
- my @words;
- substr($text,$inputline->get('text_position'),0,"\0");
- while ($text =~ /("(?:[^"\\]*(?:\\.[^"\\]*)*)")[ ,]*|([^ ,]+)[ ,]*|[ ,]+/g) {
- $word = defined $1 ? $1 : $2;
- if (($p = index($word, "\0")) >= 0) {
- $idx=$i; $pos=$p;
- substr ($word, $p, 1, "");
- }
- $i++;
- push(@words,$word);
- }
- ($idx,$pos,@words);
- }
-
- sub set_words {
- my $text=shift;
- $text.=" ".join(",",@_) if scalar@_;
- my $pos=index($text,"\0");
- if ($pos) {
- substr($text,$pos,1,"");
- $inputline->set_text($text);
- $inputline->set_position($pos);
- } else {
- $inputline->set_text($text);
- }
- }
-
- my $last_func;
- my $last_arg;
-
- my %type2str = (
- &PDB_BOUNDARY => 'BOUNDARY',
- &PDB_CHANNEL => 'CHANNEL',
- &PDB_COLOR => 'COLOR',
- &PDB_DISPLAY => 'DISPLAY',
- &PDB_DRAWABLE => 'DRAWABLE',
- &PDB_FLOAT => 'FLOAT',
- &PDB_IMAGE => 'IMAGE',
- &PDB_INT32 => 'INT32',
- &PDB_FLOATARRAY => 'FLOATARRAY',
- &PDB_INT16 => 'INT16',
- &PDB_PARASITE => 'PARASITE',
- &PDB_STRING => 'STRING',
- &PDB_PATH => 'PATH',
- &PDB_INT16ARRAY => 'INT16ARRAY',
- &PDB_INT8 => 'INT8',
- &PDB_INT8ARRAY => 'INT8ARRAY',
- &PDB_LAYER => 'LAYER',
- &PDB_REGION => 'REGION',
- &PDB_STRINGARRAY => 'STRINGARRAY',
- &PDB_SELECTION => 'SELECTION',
- &PDB_STATUS => 'STATUS',
- &PDB_INT32ARRAY => 'INT32ARRAY',
- );
-
- sub setheight {
- my($w,$y)=@_;
- $w->set_usize(-1, ($w->style->font->ascent + $w->style->font->descent) * $y);
-
- }
-
- sub new_cinfo {
- $cinfo->freeze;
- $cinfo->clear;
-
- my $add_split = sub {
- my($t,$n,$d)=@_;
- $d=~s/^(.{40,60})[ \t]*([\{[:\(])/$1\n$2/mg;
- for(split/\n/,Gimp::wrap_text($d,60)) {
- $cinfo->append("",$t,$n,$_);
- $t=$n="";
- }
- };
-
- if($args) {
- $cinfo->append("In:","","","");
- for(@args) {
- $add_split->($type2str{$_->[0]},$_->[1],$_->[2]);
- }
- }
- if($results) {
- $cinfo->append("Out:","","","");
- for(0..$results-1) {
- my($type,$name,$desc)=Gimp->procedural_db_proc_val ($last_func, $_);
- $add_split->($type2str{$type},$name,$desc);
- }
- }
-
- $cinfo->thaw;
- }
-
- sub set_current_function {
- my $fun = shift;
- return if $last_func eq $fun || !$function{$fun};
- $last_func = $fun;
- $last_arg = 0;
- @args=();
- eval {
- $function{$fun} or die;
- ($blurb,$help,$author,$copyright,$date,$type,$args,$results)=
- Gimp->procedural_db_proc_info($fun);
- $blurb_label->set($blurb);
- for(0..$args-1) {
- push(@args,[Gimp->procedural_db_proc_arg($fun,$_)]);
- }
- new_cinfo;
-
- $help_text->delete_text(0,-1);
- $help_text->insert_text($help,0);
- $author_label->set($author);
- $copyright_label->set($copyright);
- $date_label->set($date);
- eval {
- my ($menupath, $accel, $path, $imagetypes, $mtime) = @{$plugin_info{$fun}};
- $menupath_label->set($menupath);
- $accelerator_label->set($accel);
- $plugin_path_label->set($path);
- $imagetypes_label->set($imagetypes);
- $last_modified_label->set(strftime("%Y-%m-%d %H:%M:%S (%Z)", localtime ($mtime)));
- };
- warn $@ if $@;
- };
- warn $@ if $@;
- }
-
- sub set_clist {
- $clist->freeze;
- $clist->clear;
- @completion = ();
- @compdata = ();
- while(@_) {
- $clist->append(@_[0]);
- push @completion, shift;
- push @compdata, shift;
- }
- $clist->thaw;
- }
-
- sub complete_function {
- my $name = shift;
- $name=~s/[-_]/[-_]/g;
- my @matches = eval { sort grep /$name/i,@function };
- if(@matches>1) {
- set_clist map(($_,$_),@matches);
- $synopsis->set(scalar@matches.__" matching functions");
- } else {
- set_clist @matches,@matches;
- $synopsis->set($matches[0].__" (press Tab to complete)");
- }
- }
-
- sub complete_type {
- my($type,$name,$desc)=@_;
-
- if($type==PDB_IMAGE) {
- set_clist(map(("$$_: ".$_->get_filename,$$_),Gimp->image_list));
- } elsif($type==PDB_LAYER) {
- set_clist(map { my $i = $_; map(("$$_: ".$i->get_filename."/".$_->get_name,$$_),$i->get_layers)} Gimp->image_list);
- } elsif($type==PDB_CHANNEL) {
- set_clist(map { my $i = $_; map(("$$_: ".$i->get_filename."/".$_->get_name,$$_),$i->get_channels)} Gimp->image_list);
- } elsif($type==PDB_DRAWABLE) {
- set_clist(map { my $i = $_; map(("$$_: ".$i->get_filename."/".$_->get_name,$$_),($i->get_layers,$i->get_channels))} Gimp->image_list);
- } elsif ($type==PDB_INT32) {
- if ($name eq "run_mode") {
- set_clist("RUN_NONINTERACTIVE","RUN_NONINTERACTIVE",
- "RUN_INTERACTIVE","RUN_INTERACTIVE",
- "RUN_WITH_LAST_VALS","RUN_WITH_LAST_VALS");
- } elsif ($desc=~s/(?::\s*)?{(.*)}.*?$//) {
- $_=$1;
- my @args;
- while(s/^.*?([A-Za-z_-]+)\s*\(\s*(\d+)\s*\)//) {
- push(@args,"$2: $1",$2);
- }
- set_clist(@args);
- } else {
- set_clist;
- }
- } else {
- set_clist;
- }
- $synopsis->set($desc);
- }
-
- sub update_completion {
- my($idx,$pos,@words)=get_words;
-
- return unless $idx ne $last_arg;
- $last_arg=$idx;
-
- set_current_function $words[0];
-
- if ($idx == 0) {
- complete_function($words[0]);
- } elsif ($idx>@args) {
- $synopsis->set(__"too many arguments");
- set_clist;
- } else {
- complete_type(@{$args[$idx-1]});
- }
- }
-
- sub do_completion {
- update_completion;
-
- my($idx,$pos,@words)=get_words;
- my($word)=$words[$idx];
-
- $word=~s/[-_]/[-_]/g;
- my(@matches)=grep /$word/i,@completion;
- my $new;
- if (@matches>1) {
- if (join("\n",@matches) =~ ("^(".$words[$idx].".*).*?".("\n\\1.*" x scalar@matches-1))) {
- $new=$1;
- }
- } elsif(@matches==1) {
- $new=$compdata[0];
- } else {
- Gtk::Gdk->beep;
- }
- if (defined $new) {
- $words[$idx]=$new;
- set_current_function $words[0] if $idx==0;
- if($idx<@args) {
- $words[$idx+1]="\0".$words[$idx+1];
- } else {
- $words[$idx].="\0";
- }
- set_words @words;
- }
- undef $last_arg;
- }
-
- sub execute_command {
- my($idx,$pos,$fun,@args)=get_words;
- $res=eval { Gimp->$fun(@args) };
- if ($@) {
- $statusbar->set($@);
- $result->set_text("");
- Gtk::Gdk->beep;
- } else {
- $statusbar->set('');
- $result->set_text($res);
- $rlist->prepend_items(new Gtk::ListItem $res);
- }
- }
-
- sub idle {
- Gtk->idle_remove($idle) if $idle;
- undef $idle;
- update_completion;
- }
-
- sub do_idle {
- $idle=Gtk->idle_add(\&idle) unless $idle;
- }
-
- eval "use Gtk::Keysyms ()";
- $Gtk::Keysyms{Tab} ||= 0xFF09;
-
- sub inputline {
- my $e = new Gtk::Entry;
- $e->set_text("");
- $e->signal_connect("changed",sub {
- undef $last_arg;
- do_idle;
- });
- $e->signal_connect("focus_in_event",\&do_idle);
- $e->signal_connect("button_press_event",\&do_idle);
- $e->signal_connect("key_press_event",sub {
- undef $last_arg;
- do_idle;
- if ($_[1]->{keyval} == $Gtk::Keysyms{Tab}) {
- $_[0]->signal_emit_stop_by_name('key_press_event');
- do_completion;
- 1;
- } else {
- ();
- }
- });
- $e->signal_connect("activate",\&execute_command);
- #$e->set_usize($ex*40,0);
- $inputline=$e;
-
- my $c = new Gtk::CList(1);
- setheight $c, 6;
- $clist = $c;
- $c->set_selection_mode(-extended);
- $c->signal_connect("select_row", sub {
- eval {
- my($idx,$pos,@words)=get_words;
- $words[$idx]=$compdata[$_[1]]."\0";
- set_words (@words);
- set_current_function (substr($words[0],0,-1)) unless $idx;
- };
- do_idle;
- });
-
- my $r = new Gtk::List;
- $rlist = $r;
- $r->set_selection_mode(-single);
- $r->set_selection_mode(-browse);
- }
-
- sub info {
- my $info = new Gtk::Dialog;
- $info->set_title(__"Function Info");
- $info->signal_connect(delete_event => sub { $info->hide });
-
- my $close = new Gtk::Button __"Close";
- $close->signal_connect(clicked => sub { $info->hide });
- $info->action_area->add($close);
-
- my $table = new Gtk::Table 2,9+1,0;
- my $y = 0;
- $info->vbox->add($table);
-
- local *add_info = sub {
- my ($label, $widget, $large) = @_;
- $label = new Gtk::Label $label.": ";
- $label->set_alignment(0, 0);
- $table->attach($label,0,1,$y,$y+1,[-fill],[-fill],0,0);
- if ($large) {
- $y++;
- $table->attach($widget,0,2,$y,$y+$large,[-expand,-fill],[-expand,-fill],0,0);
- $y+=$large;
- } else {
- $widget->set_alignment(0, 0);
- $table->attach($widget,1,2,$y,$y+1,[-fill],[-fill],0,0);
- $y++;
- }
- };
-
- $blurb_label = new Gtk::Label;
- add_info(__"Menu Path", $menupath_label = new Gtk::Label);
- add_info(__"Accelerator", $accelerator_label = new Gtk::Label);
- add_info(__"Image Types", $imagetypes_label = new Gtk::Label);
- add_info(__"Author", $author_label = new Gtk::Label);
- add_info(__"Copyright", $copyright_label = new Gtk::Label);
- add_info(__"Date/Version", $date_label = new Gtk::Label);
- add_info(__"Last Modified", $last_modified_label = new Gtk::Label);
- add_info(__"Plug-In Path", $plugin_path_label = new Gtk::Label);
-
- $help_text = new Gtk::Text;
- $help_text->set_editable(0);
- $help_text->set_word_wrap(1);
- my $cs = new Gtk::ScrolledWindow undef,undef;
- $cs->set_policy(-automatic,-automatic);
- $cs->add ($help_text);
- add_info (__"Description", $cs, 2);
-
- my $h = new Gtk::HBox(0,5);
- my $more = new Gtk::Button __"More...";
- $more->signal_connect(clicked => sub { $info->visible ? $info->hide : $info->show_all });
- $h->add($blurb_label);
- $h->add($more);
- $h;
- }
-
- sub create_main {
- my $b;
- my $t;
-
- $t = new Gtk::Tooltips;
- my $w = new Gtk::Dialog;
- $window = $w;
- $w->realize;
- $ex = $w->style->font->string_width ('Mn')*0.5;
- $ey = $w->style->font->string_width ('My');
-
- $w->set_title(__"PDB Explorer - the olof edition (yet still an alpha version)");
- $w->signal_connect("destroy",sub {main_quit Gtk});
-
- $b = new Gtk::Button __"Close";
- $w->action_area->add($b);
- $b->signal_connect("clicked",sub {main_quit Gtk});
-
- my $vpane = new Gtk::VPaned; $w->vbox->add($vpane);
- $vpane->add1(my $f1 = new Gtk::VBox 0,0);
- $vpane->add2(my $f2 = new Gtk::VBox 0,0);
-
- my $h = new Gtk::HBox (0,5);
- $f1->pack_start ($h,0,0,0);
-
- inputline;
-
- $synopsis = new Gtk::Label "";
- $synopsis->set_justify(-left);
-
- my $table = new Gtk::Table 3,4,0;
- $f1->pack_start($table,1,1,0);
-
- my $cs = new Gtk::ScrolledWindow undef,undef;
- $cs->set_policy(-automatic,-automatic);
- $cs->add ($clist);
- #$cs->set_usize(0,$ey*6);
-
- my $rs = new Gtk::ScrolledWindow undef,undef;
- $rs->set_policy(-automatic,-automatic);
- $rs->add_with_viewport ($rlist);
-
- $result = new Gtk::Entry;
- $result->set_editable(0);
- #$result->set_usize($ex*30,0);
-
- $statusbar = new Gtk::Label;
-
- $table->border_width(10);
-
- $table->attach(new Gtk::Label(__"Synopsis") ,0,1,0,1,{},{},0,0);
- $table->attach($synopsis ,1,2,0,1,{},{},0,0);
- $table->attach(Gimp::UI::logo($w),2,3,0,1,{},{},0,0);
- $table->attach(new Gtk::Label(__"Command") ,0,1,1,2,{},{},0,0);
- $table->attach($inputline,1,3,1,2,['expand','fill'],{},0,0);
- # $table->attach($result,2,3,1,2,['expand','fill'],{},0,0);
- $table->attach(new Gtk::Label(__"Shortcuts"),0,1,2,3,{},{},0,0);
- $table->attach($cs ,1,3,2,3,['expand','fill'],['expand','fill'],0,0);
- # $table->attach($rs,2,3,2,3,['expand','fill'],['expand','fill'],0,0);
- $table->attach(new Gtk::Label(__"Status"),0,1,3,4,{},{},0,0);
- $table->attach($statusbar,1,3,3,4,{},{},0,0);
-
- $f2->pack_start(info,0,1,5);
- my $sw = new Gtk::ScrolledWindow;
- $sw->set_policy(-automatic, -automatic);
- $cinfo = new_with_titles Gtk::CList '',__"TYPE",__"NAME",__"DESCRIPTION";
- $cinfo->set_column_auto_resize (0,1);
- $cinfo->set_column_auto_resize (1,1);
- $cinfo->set_column_auto_resize (2,1);
- $cinfo->set_selection_mode('single');
- setheight $cinfo, 8;
- $sw->add ($cinfo);
- $f2->pack_start ($sw,1,1,5);
-
- idle;
-
- $w->realize;
- show_all $w;
- }
-
- register "extension_pdb_explorer",
- "Procedural Database Explorer",
- "This is a more interactive and less broken / script-fu-centric version of the DB Browser",
- "Marc Lehmann",
- "Marc Lehmann",
- "0.4alpha",
- N_"<Toolbox>/Xtns/PDB Explorer...",
- "",
- [],
- sub {
-
- Gimp::gtk_init;
- refresh;
- create_main;
- main Gtk;
-
- ();
- };
-
- exit main;
-
-